package cur.nature.component.quartz.service;

import cur.nature.component.quartz.common.AsyncExampleJob;
import cur.nature.component.quartz.dao.Component_QuartzDao;
import cur.nature.component.quartz.model.Component_QuartzPO;
import cur.nature.component.quartz.model.Component_QuartzVO;
import cur.nature.framework.core.exception.BizException;
import cur.nature.framework.core.util.ObjectUtil;
import cur.nature.framework.mvc.crud.CrudService;
import cur.nature.framework.mvc.util.CronUtil;
import cur.nature.tinyorm.core.bean.PageBean;
import cur.nature.framework.core.log.LOG;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

/**
 * 任务调度 Service
 * 作者：Auto Generator By wujian
 * 生成日期：2023-10-11 21:44:26
 */
@Service
@ConditionalOnProperty( value = {"cur.component.quartz.enable"})
public class Component_QuartzService extends CrudService<Component_QuartzPO, Component_QuartzVO, Component_QuartzDao> {
    public Component_QuartzService(Component_QuartzDao baseDao) {
        super(baseDao, Component_QuartzPO.class, Component_QuartzVO.class);
    }

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    public void refresh() throws Exception {
        LOG.info(" --------开始quartz同步调度信息-------------");
        Component_QuartzVO.list_Param param = new Component_QuartzVO.list_Param();
        List<Component_QuartzVO> tableList = getDao().list(param);
        List<Component_QuartzVO.QuartzVO> quartzList = getDao().listQuartz(null, null);
        List<Component_QuartzVO.QuartzVO> addList = new ArrayList<>();
        List<Component_QuartzVO.QuartzVO> deleteList = new ArrayList<>();
        for (int i = 0; i < 1; i++) {
            // 当tableList为空，quartzList为空时, 返回
            if(ObjectUtil.isEmpty(tableList) && ObjectUtil.isEmpty(quartzList)){
                break;
            }
            // 当tableList为空，quartzList不为空时, 删除
            if(ObjectUtil.isEmpty(tableList) && ObjectUtil.isNotEmpty(quartzList)){
                deleteList.addAll(quartzList);
                break;
            }
            // 当tableList不为空，quartzList为空时, 新增
            if(ObjectUtil.isNotEmpty(tableList) && ObjectUtil.isEmpty(quartzList)){
                for (Component_QuartzVO base : tableList) {
                    Component_QuartzVO.QuartzVO quartzEntity = this.setQuartzEntity(base);
                    addList.add(quartzEntity);
                }
                break;
            }
            // 当tableList存在，quartzList不存在时,新增;
            for (Component_QuartzVO schedule : tableList) {
                Optional<Component_QuartzVO.QuartzVO> optional = quartzList.stream().filter(s ->
                        (s.getJobGroupCode().equals(schedule.getJobGroupCode()) && s.getJobCode().equals(schedule.getJobCode()))).findFirst();
                if(!optional.isPresent()){
                    Component_QuartzVO.QuartzVO quartzEntity = this.setQuartzEntity(schedule);
                    addList.add(quartzEntity);
                }
            }
            // 当tableList不存在, quartzList存在时, 删除;
            for (Component_QuartzVO.QuartzVO quartzVO : quartzList) {
                boolean present = tableList.stream().filter(s ->
                        (s.getJobGroupCode().equals(quartzVO.getJobGroupCode()) && s.getJobCode().equals(quartzVO.getJobCode()))).findFirst().isPresent();
                if(!present){
                    deleteList.add(quartzVO);
                }
            }
        }

        // 执行新增
        if(ObjectUtil.isNotEmpty(addList)){
            for (Component_QuartzVO.QuartzVO quartzVO : addList) {
                this.addCronJob(quartzVO);
            }
        }
        // 执行删除
        if(ObjectUtil.isNotEmpty(deleteList)){
            for (Component_QuartzVO.QuartzVO quartzVO : deleteList) {
                this.deleteJob(quartzVO.getJobGroupCode(), quartzVO.getJobCode());
            }
        }
        // 更新任务状态
        if(ObjectUtil.isNotEmpty(tableList)){
            for (Component_QuartzVO base : tableList) {
                if("PAUSED".equals(base.getState())){// PAUSED-暂停
                    if(!this.isJobPaused(base.getJobGroupCode(), base.getJobCode())){
                        this.pauseJob(base.getJobGroupCode(), base.getJobCode());
                    }
                }else if("ACQUIRED".equals(base.getState())){// ACQUIRED-运行
                    if(this.isJobPaused(base.getJobGroupCode(), base.getJobCode())){
                        this.resumeJob(base.getJobGroupCode(), base.getJobCode());
                    }
                }
            }
        }
        LOG.info(" --------结束quartz同步调度信息-------------");
    }

    public PageBean<Component_QuartzVO> list(Component_QuartzVO.list_Param param) throws Exception {
        PageBean<Component_QuartzVO> list = getDao().listPage(param);
        return list;
    }

    public int saveList(List<Component_QuartzVO> list) throws Exception {
        int result = 0;
        for (Component_QuartzVO vo : list) {
            // 校验cron表达式是否有效
            if (!CronUtil.isValidExpression(vo.getCronExpression())) {
                throw new BizException("表达式无效: " + vo.getCronExpression());
            }
            result += saveEnt(vo);
        }
        return result;
    }

    public int saveEnt(Component_QuartzVO param) throws Exception {
        Component_QuartzVO.QuartzVO quartzEntity = this.setQuartzEntity(param);
        if(param.getId() == null){// 新增任务
            this.addCronJob(quartzEntity);
        }else {// 修改任务
            //根据id 查出相应的实体
            Component_QuartzVO.list_Param condition = new Component_QuartzVO.list_Param();
            condition.setIdList(Arrays.asList(param.getId()));
            List<Component_QuartzVO> list = getDao().list(condition);
            // 更新调度里的任务状态
            if(ObjectUtil.isNotEmpty(list)){
                Component_QuartzVO base = list.get(0);
                if("PAUSED".equals(param.getState())){// PAUSED-暂停
                    if(!this.isJobPaused(base.getJobGroupCode(), base.getJobCode())){
                        this.pauseJob(base.getJobGroupCode(), base.getJobCode());
                    }
                }else if("ACQUIRED".equals(param.getState())){// ACQUIRED-运行
                    if(this.isJobPaused(base.getJobGroupCode(), base.getJobCode())){
                        this.resumeJob(base.getJobGroupCode(), base.getJobCode());
                    }
                }
            }
            // 更新任务内容
            this.modifyJob(quartzEntity);
        }

        //更新任务表
//        Component_SchedulerPO po = JsonUtil.copyObj(param, Component_SchedulerPO.class);
        int rows = this.save(param);
        return rows;
    }

    private Component_QuartzVO.QuartzVO setQuartzEntity(Component_QuartzVO param){
        Component_QuartzVO.QuartzVO quartzEntity = new Component_QuartzVO.QuartzVO();
        quartzEntity.setSchedCode(param.getSchedCode());
        quartzEntity.setJobGroupCode(param.getJobGroupCode());
        quartzEntity.setJobCode(param.getJobCode());
        quartzEntity.setCronExpression(param.getCronExpression());
        quartzEntity.setJobClass(param.getJobClass());
        quartzEntity.setJobData(param.getJobData());
        quartzEntity.setDescription(param.getRemark());
        return quartzEntity;
    }

    public void modifyJob(Component_QuartzVO.QuartzVO quartzEntity) {
        LOG.info("------------修改任务信息开始-------------------");
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            //TriggerKey triggerKey1 = TriggerKey.triggerKey(triggerKey.getName(), triggerKey.getGroup());
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzEntity.getJobCode() + "_trigger", quartzEntity.getJobGroupCode() + "_trigger");
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) { return; }
            String oldTime = trigger.getCronExpression();
            JobKey jobKey = JobKey.jobKey(quartzEntity.getJobCode(), quartzEntity.getJobGroupCode());
            JobDetail jobDetail = null;
            String oldJobData = null;
            Class<? extends Job> oldJobClass = null;
            Class<? extends Job> newJobClass = (Class<? extends Job>) Class.forName(quartzEntity.getJobClass());
            // 如果class不存在, 则获取detail时会报错
            try {
                jobDetail = scheduler.getJobDetail(jobKey);
                oldJobData = jobDetail.getJobDataMap().getString("taskData");
                oldJobClass = jobDetail.getJobClass();
            } catch (Exception ex) {
                LOG.error("find jobdetail error. " ,ex);
            }
            // cron 不相等
            if (!ObjectUtils.nullSafeEquals(oldTime, quartzEntity.getCronExpression())) {
                LOG.info("------------修改任务cron信息-------------------");
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzEntity.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing();
                //按新的cronExpression表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startAt(new Date())
                        .withSchedule(scheduleBuilder).build();
                scheduler.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间

            }
            // data 内容不相等
            if (!ObjectUtils.nullSafeEquals(oldJobData, quartzEntity.getJobData()) || (oldJobClass != newJobClass)) {
                LOG.info("------------修改任务jobData信息-------------------");
                //构建job信息
                Map<String, String > dataMap = new HashMap<>();
                dataMap.put("taskData", quartzEntity.getJobData());
                jobDetail = JobBuilder.newJob(newJobClass).withIdentity(quartzEntity.getJobCode(), quartzEntity.getJobGroupCode())
                        .usingJobData(new JobDataMap(dataMap)).storeDurably(true).build();
                scheduler.addJob(jobDetail,true);
            }
        } catch (Exception ex) {
            LOG.error("修改任务异常：", ex);
        }
        LOG.info("------------结束修改任务信息-------------------");
    }

    /**
     * 创建一个定时任务
     *
     * @param quartzEntity
     */
    public void addCronJob(Component_QuartzVO.QuartzVO quartzEntity) {
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            JobKey jobKey = JobKey.jobKey(quartzEntity.getJobCode(), quartzEntity.getJobGroupCode());
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail != null) {
                LOG.warn("job:" + quartzEntity.getJobCode() + " 已存在");
            } else {
                //构建job信息
                Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzEntity.getJobClass());
                jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzEntity.getJobCode(), quartzEntity.getJobGroupCode()).storeDurably().build();
                //用JopDataMap来传递数据
                jobDetail.getJobDataMap().put("taskData", quartzEntity.getJobData());

                //表达式调度构建器(即任务执行的时间,每5秒执行一次)
//                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?")
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzEntity.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing();

                //按新的cronExpression表达式构建一个新的trigger
                CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzEntity.getJobCode() + "_trigger", quartzEntity.getJobGroupCode() + "_trigger")
                        .withSchedule(scheduleBuilder).build();
                scheduler.scheduleJob(jobDetail, trigger);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void addAsyncJob(Component_QuartzVO.QuartzVO quartzEntity) throws BizException, SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();

        JobKey jobKey = JobKey.jobKey(quartzEntity.getJobCode(), quartzEntity.getJobGroupCode());
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail != null) {
            LOG.warn("job:" + quartzEntity.getJobCode() + " 已存在");
            throw new BizException("job:" + quartzEntity.getJobCode() + " 已存在");
        }
        //构建job信息,在用JobBuilder创建JobDetail的时候，有一个storeDurably()方法，可以在没有触发器指向任务的时候，将任务保存在队列中了。然后就能手动触发了
        jobDetail = JobBuilder.newJob(AsyncExampleJob.class).withIdentity(quartzEntity.getJobCode(), quartzEntity.getJobGroupCode()).storeDurably().build();
        jobDetail.getJobDataMap().put("asyncData","this is a async task");
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzEntity.getJobCode() + "_trigger", quartzEntity.getJobGroupCode() + "_trigger") //定义name/group
                .startNow()//一旦加入scheduler，立即生效
                .withSchedule(simpleSchedule().withMisfireHandlingInstructionIgnoreMisfires())//使用SimpleTrigger
                .build();
        scheduler.scheduleJob(jobDetail, trigger);


    }

    public void pauseJob(String jobGroupCode, String jobCode) {
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            // 假设你已经有了一个JobKey，这里是模拟的
            JobKey jobKey = new JobKey(jobCode, jobGroupCode);
            // 暂停任务
            scheduler.pauseJob(jobKey);

//            TriggerKey triggerKey = TriggerKey.triggerKey(jobCode + "_trigger", jobGroupCode + "_trigger");
//            scheduler.pauseTrigger(triggerKey);
            LOG.info("=========================pause job:" + jobCode + " success========================");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public boolean isJobPaused(String jobGroupCode, String jobCode) {
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobCode + "_trigger", jobGroupCode + "_trigger");

            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            if (Trigger.TriggerState.PAUSED.equals(triggerState)) {
                return true;
            }
            LOG.info("=========================is Job Paused:" + jobCode + " success========================");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 恢复任务
     *
     * @param jobCode
     * @param jobGroupCode
     */
    public void resumeJob(String jobGroupCode, String jobCode) {
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            // 假设你已经有了一个JobKey，这里是模拟的
            JobKey jobKey = new JobKey(jobCode, jobGroupCode);
            // 暂停任务
            scheduler.resumeJob(jobKey);

//            TriggerKey triggerKey = TriggerKey.triggerKey(jobCode + "_trigger", jobGroupCode + "_trigger");
//            scheduler.resumeTrigger(triggerKey);
            LOG.info("=========================resume job:" + jobCode + " success========================");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void deleteJob(String jobGroupCode, String jobCode) {
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            JobKey jobKey = JobKey.jobKey(jobCode,jobGroupCode);
            boolean isSuccess = scheduler.deleteJob(jobKey);
            LOG.info("=========================delete job:" + jobCode + (isSuccess ? "成功" : "失败")+" ========================");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

    public int runJob(Component_QuartzVO param) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(param.getJobCode(),param.getJobGroupCode());
        schedulerFactoryBean.getScheduler().triggerJob(jobKey);
        return 1;
    }
}

